package com.hulk.rpc.invoke;

import com.google.common.base.Strings;
import com.hulk.rpc.annotation.HulkService;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Method;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author xuxukang
 */
public interface InvokerUtils {

  /**
   * @param group 不能包含# /
   * @param app   不能包含# /
   * @param clazz 不能为空
   */
  static String getServiceClassName(String group, String app, Class<?> clazz) {
    if (StringUtils.isBlank(group)) {
      group = HulkService.default_group;
    }

    if (StringUtils.isBlank(app)) {
      app = HulkService.default_app;
    }

    check(group, app);

    return group + "#" //
            + app + "#" //
            + clazz.getName();
  }

  /**
   * app
   *
   * @param group  不能包含#
   * @param app    不能包含#
   * @param method 不能为空
   */
  static String getServiceMethodName(String group, String app, Method method) {
    if (group == null || group.trim().length() == 0) {
      group = HulkService.default_group;
    }

    if (app == null || app.trim().length() == 0) {
      app = HulkService.default_app;
    }

    check(group, app);

    String version = HulkService.default_version;

    HulkService config = method.getAnnotation(HulkService.class);
    if (config == null) {
      config = method.getDeclaringClass().getAnnotation(HulkService.class);
    }

    if (config != null) {
      version = config.version();
    }

    int delimeterIndex = version.indexOf('.');
    if (delimeterIndex > 0) {
      version = version.substring(0, delimeterIndex);
    }

    Class<?>[] parameterTypes = method.getParameterTypes();

    String params = Stream.of(parameterTypes)//
            .map(Class::getName)//
            .collect(Collectors.joining(",", "(", ")"));

    return group + "#" //
            + app + "#" //
            + method.getDeclaringClass().getName() //
            + "#" + method.getName()//
            + "#" + params//
            + "#v" + version;
  }

  static void check(String group, String app) {
    if (group.contains("#")) {
      throw new RuntimeException("group不能包含#");
    }

    if (group.contains("/")) {
      throw new RuntimeException("group不能包含/");
    }

    if (app.contains("#")) {
      throw new RuntimeException("app不能包含#");
    }

    if (app.contains("/")) {
      throw new RuntimeException("app不能包含/");
    }
  }

  /**
   * 获取rest访问路径
   *
   * @param method 不能为空
   * @return 当未配置或未正确配置时返回null
   */
  static String getRestPath(Method method) {
    HulkService methodConfig = method.getAnnotation(HulkService.class);

    if (methodConfig == null) {
      return null;
    }

    String version = methodConfig.version();
    int delimterIndex = version.indexOf('.');
    if (delimterIndex > 0) {
      version = version.substring(0, delimterIndex);
    }

    String restPath = methodConfig.rest();

    if (StringUtils.isBlank(restPath)) {
      return null;
    }

    // 该方法getRestPath低频使用，没必要考虑性能问题
    while (restPath.startsWith("/")) {
      restPath = restPath.substring(1);
    }

    while (restPath.endsWith("/")) {
      restPath = restPath.substring(0, restPath.length() - 1);
    }

    HulkService classConfig = method.getDeclaringClass().getAnnotation(HulkService.class);
    if (classConfig != null) {
      String classRestPath = classConfig.rest();

      if (!Strings.isNullOrEmpty(classRestPath)) {
        while (classRestPath.startsWith("/")) {
          classRestPath = classRestPath.substring(1);
        }

        while (classRestPath.endsWith("/")) {
          classRestPath = classRestPath.substring(0, classRestPath.length() - 1);
        }

        restPath = classRestPath + "/" + restPath;
      }
    }

    restPath = restPath.replace("//", "/");

    return restPath + "?v=" + version;
  }

  static Class<?> toClass(String serviceClassName) {
    try {
      return Class.forName(serviceClassName.split("#")[2]);
    } catch (ClassNotFoundException e) {
      return null;
    }
  }

  static Method toMethod(String serviceMethodName) {
    try {
      String[] array = serviceMethodName.split("#");

      String className = array[2];
      String methodName = array[3];
      String params = array[4];

      Class<?> clazz = Class.forName(className);

      for (Method method : clazz.getMethods()) {
        if (!method.getName().equals(methodName)) {
          continue;
        }

        String _params = Stream.of(method.getParameterTypes())//
                .map(Class::getName)//
                .collect(Collectors.joining(",", "(", ")"));

        if (_params.equals(params)) {
          return method;
        }
      }

      return null;
    } catch (ClassNotFoundException e) {
      return null;
    }
  }

  interface TestInter {
    void hello(String name);
  }

  public static void main(String[] args) {
    String serviceClassName = InvokerUtils.getServiceClassName(null, null, TestInter.class);
    System.out.println(serviceClassName);

    Class<?> aClass = InvokerUtils.toClass(serviceClassName);
    assert aClass != null;
    System.out.println(aClass.getCanonicalName());
  }

}
